import es
import time
import math

import es
import playerlib
import gamethread
import vecmath
import weaponlib
import spe

import wcs.libs.effects as effects
from wcs.libs.common import * 
from wcs.libs.constants import *

__all__ = ["CommandManager"]

class CommandManager(CaseChanger):
    """
    This class manages all of the commands that WCS has to offer. Because it's
    now in a library it seperates the commands from the main engine making it
    easier to read and interpret.
    
    Each PlayerObject shall have an instance to the command manager. When that
    object is destroyed, the corrosponding Command object will be destroyed as
    well providing there are no further references.
    
    Since I have altered the styling of WCS with starting with a lowercase 
    character for function names, to ensure that I keep backwards compatibility
    I have to ensure dynamic calling of titled function names which aren't found
    
    An example of this is:
    
    +======================================================+
    |      Old Reference       |        New Refernce       |
    +==========================+===========================+
    | command-object.Distance()| command-object.distance() |
    |  command-object.Beacon() |  command-object.beacon()  |
    +======================================================+
    
    Although both references work, the second one is preferred.
    """
    
    """
    Any attributes assigned here will be accepted by the __setattr__ functon
    """
    userid     = None
    attributes = None
    
    def __init__(self, userid, playerObject):
        """
        Default constructor - ensure that we assign default values.

        @param int userid The ID of the user this command object represents
        @param wcs.Player playerObject The WCS player object for this player
        """
        self.userid     = int(userid)
        self.attributes = self.Attributes()
        self.playerObject = playerObject
        self.playerlibObject = playerlib.getPlayer(self.userid)
        
    def __del__(self):
        """
        Default deconstructor - when no references to this object exist, cancel
        any outstanding delays.
        """
        for delay in self.attributes.delayList:
            gamethread.cancelDelayed(delay)
        del self.playerObject
    
    def __getattr__(self, key):
        """
        Executed when an attribute isn't found. Assume we want to retrieve
        the value of the attribute instance.
        
        @param str key The attribute of which to retrieve
        @return mixed The values which is retrieved
        """
        try:
            return self.attributes.__getattr__(key)
        except AttributeError:
            return CaseChanger.__getattr__(self, key)
        
    def __setattr__(self, key, value):
        """
        Executed when setting the value of an attribute which doesn't exist in
        the class. Assume we want to overwrite an attribute object's attribute.
        
        @param str key The name of the attribute
        @param mixed value The value of the attribute 
        """
        if not hasattr(self.__class__, key):
            self.attributes.__setattr__(key, value)
        else:
            object.__setattr__(self, key, value)
        
    def __getitem__(self, key):
        """
        Executed when this class is treated as a dictionary and itemized.
        Attempt to return the value of the attributes class.
        
        @param str key The attribute of which to retrieve
        @return mixed The value of the attribute
        """
        try:
            return self.attributes.__getitem__(key)
        except KeyError:
            return CustomNullType()
            
    def __setitem__(self, key, value):
        """
        Executed when this class is treated as a dictionary and itemized.
        Attempt to set the value to of which the key corrolates within the
        attributes class.
        
        @param str key The attribute of which to assign a value
        @param mixed value The value which is assigned to the attribute
        """
        self.attributes.__setitem__(key, value)
        
    def __delitem__(self, key):
        """
        Executed when we wish to remove an item directly from the player's
        attribute object singleton instance. This will ocurr when races wish
        to clear up specific attributes (custom) which they have assigned.
        Obviously not everyone will know how to do this, but it's not a huge
        deal as the memory usage shouldn't be too huge. Obviously removing is
        safe, as if we attempt to access an attribute which doesn't exist, we
        shall return the custom null type which should default to None or null
        type objects in all situations regarding comparison and what not.
        
        @param str key The attribute of which to remove
        """
        if key in self.attributes:
            del self.attributes[key]
            
    def __repr__(self):
        """
        How this class is represented in python. Return a string which
        simulates this object.
        """
        return "CommandManager(Player(%s))" % self.userid

    def __contains__(self, key):
        """
        Executed when we wish to test if an item exists within this instance.
        Assume we want to see if an object exists within the attribute
        dictionary.

        @param object key The object to test for existence
        @return bool Whether or not the object exists
        """
        return self.attributes.__contains__(key)
        
    def distance(self, target):
        """
        Returns the distance between two players in game units.
        
        @param userid target The target ID to use as the distance target
        """
        v1 = vecmath.Vector(es.getplayerlocation(self.userid))
        v2 = vecmath.Vector(es.getplayerlocation(target))
        return (v1 - v2).length()
        
    def beaconTimed(self, duration):
        """
        Begins a timed beacon which iterates every second until the duration
        ends.
        
        @param int duration The time to keep the beacon active for
        """
        self.beacon()
        for i in xrange(int(duration)):
            self.delayedName(i + 1, "beacon_%s" % i, self.beacon)
        
    def beacon(self):
        """ Creates a beacon around the player """
        x, y, z = es.getplayerlocation(self.userid)
        effects.RingCustom("#a", 0, "sprites/purpleglow1.vmt", x, y, z + 35,
                                    100, 350, .5, 4, 2, 2, 255, 0, 0, 255, 100)
        es.emitsound('player', self.userid, BLIP, 1.0, 0.5)

    def hudHint(self, text):
        """
        Displays a message within the HUDHint location on the player's screen;
        (the centre of the bottom of the screen).

        @param string text The text to display in the area.
        """
        es.usermsg('create', 'hudhint', 'HintText')
        es.usermsg('write',  'short',   'hudhint', -1)
        es.usermsg('write',  'string',  'hudhint', text)
        es.usermsg('send',   'hudhint', self.userid)
        es.usermsg('delete', 'hudhint')

    def blockUlti(self, duration=None):
        """
        Prevents this particular player from accessing their ultimate for
        a certain amount of time.

        @param optional integer duration The amount of time to block the
                                         ultimate
        """
        self.__setitem__('blockUltimate', True)
        if duration is not None and duration > 0:
            gamethread.delayed(duration, self.__seitem__, ('BlockUltimate',
                                                            False))

    def blockAbil(self, duration=None):
        """
        Prevents this particular player from accessing their ability for
        a certain amount of time.

        @param optional integer duration The amount of time to block the
                                         ability
        """
        self.__setitem__('blockAbility', True)
        if duration is not None and duration > 0:
            gamethread.delayed(duration, self.__setitem__, ('blockAbility',
                                                            False))

    def setCoolDown(self, skill, duration):
        """
        Apply a cooldown (or time limit) to a skill which prevents them from
        using the skill until the time has passed.
        
        @param string skill The name of the skill
        @param integer duration The time the cooldown is applied for
        """
        from wcs.libs.races import races
        
        raceObject = self.playerObject[self.playerObject.currentRace]
        if skill in races[self.playerObject.currentRace]:
            raceObject[skill].coolDown = duration

    def getCoolDown(self, skill):
        """
        Returns the time in whole seconds until a player can execute their
        skill. We ceiling the value so we get an actual integral value rather
        than a very long floatation number.

        @param string skill The name of the skill to obtain
        @return integer The time remaining on the cooldown of the skill
        """
        from wcs.libs.races import races
        
        raceObject = self.playerObject[self.playerObject.currentRace]
        if skill in races[self.playerObject.currentRace]:
            if raceObject[skill].coolDown:
                return int(raceObject[skill].coolDown) + 1 
        return 0

    def returnUserKey(self):
        """
        Return's the attributes of the player. This will contain all of the
        player specific attributes in a dictionary form. This method of
        obtaining the user key is deprecated on not recommended to be used in
        favour of the __getitem__ operator directly on the command instnace.

        @depricated
        @return Attributes The attributes for this player
        """
        return self.attributes

    def returnDict(self, key):
        """
        Obtain the value in the player's attributes. This is just to extend the
        functionality of __getitem__ by applying a function wrapper for
        backwards compatibility. This method is deprecated for the instance[]
        method.

        @depricated
        @param string key The name of the key to obtain the value for
        @return object The value which is represented by the key
        """
        return self.__getitem__(key)

    def updateDict(self, key, value):
        """
        Adds a key-value pair to the attribute table. This method of updating
        the attribute table is deprecated and not recommended over the
        __setiem__ method.

        @depricated
        @param object key The key of the key-value pair
        @param object value The value of the key-value pair
        """
        self.__setitem__(key, value)

    def modDict(self, key, value):
        """
        Modifies a player's attributes by incrementing the key by value. This
        is essentially updating the attribute with a "+=" rather than assigning
        a new value.
        
        This method is deprecated and the new method would be the += operator
        on the __getitem__ / __setitem__ dict operators. This is here for
        backwards compatibility only
        
        @depricated
        @param object key The key of the key-value pair
        @param integer value A value to increment the current value by
        """
        if key in self.attributes:
            self.attributes[key] += value

    def regen(self, health, delay):
        """
        Creates and starts a loop which will regularly heal the player by
        specified amounts. We can explicitly stop the regen at any point
        by the stopRegen function.

        @param int health Amount of health to add each delay tick
        @param float delay The amount of seconds in between each regen delay
        """
        self.cancelDelayed("regen")
        health  = self.playerlibObject.health
        health += health
        maxHealth = self.attributes['maxHealth']
        health = min(maxHealth, health)
        self.playerlibObject.health = health
        self.delayedName(delay, "regen", self.regen, (health, delay))

    def stopRegen(self):
        """
        Stops any current regeneration for this user.
        """
        self.cancelDelayed("regen")

    def damage(self, damage, damageType=32, attacker=0, weapon=None):
        """
        This command will be an alternative to the regular damage command. This
        will enable us to damage a player and possibly credit another. Because
        of the functionality of WCS scripts, we need to not cause damage unless
        it is certain to kill them; otherwise the damage event itself may force
        other damage events which can go into an endless loop.

        @param int damage Amount of damage to deal
        @param int damageType The type of damage to deal (32 = fall damage)
        @param int attacker An attacker to credit for the damage (0 = self)
        """
        if self.playerlibObject.health <= damage:
            weapon = weaponlib.getWeapon(weapon)
            if not attacker:
                attacker = self.userid
            index = self.playerlibObject.index
            targetName = es.entitygetvalue(index, "targetname")
            es.setentityname(index, "wcs_damage_player")
            es.server.es_fire(attacker, "point_hurt", "kill")
            index = es.createentity("point_hurt")
            es.entitysetvalue(index, "Damage", damage)
            es.entitysetvalue(index, "DamageType", damageType)
            es.entitysetvalue(index, "DamageTarget", "wcs_damage_player")
            if not weapon and attacker != self.userid:
                attackerlibObject = playerlib.getPlayer(attacker)
                weapon = weaponlib.getWeapon(attackerlibObject.weapon)
            if weapon:
                es.entitysetvalue(index, "classname", weapon.name)
            es.spawnentity(index)
            es.server.es_fire(attacker, "point_hurt", "Hurt")
            es.setentityname(index, targetName)
        else:
            self.heal(damage * -1)

    def color(self, colorCode=None, red=255, green=255, blue=255, alpha=None):
        """
        This command changes a player's model colour with the possibility of
        altering their alpha as well. This makes everybody on the server see
        the player as a different colour / transparacny. This also sets the
        player's weapon colour.

        @param string colorCode A valid string such as "red" or "blue"
        @param int red A red value for the colour (0 - 255)
        @param int green A green value for the colour (0 - 255)
        @param int blue A blue value for the colour (0 - 255)
        @param int alpha The alpha transparency of the model (0 - 255)
        """
        if colorCode is not None:
            if colorCode in COLORS:
                red, green, blue = COLORS[colorCode]
        if alpha is None:
            alpha = self.playerlibObject.getColor()[3]
        else:
            self.attributes['minAlpha'] = alpha
        self.playerlibObject.setColor(red, green, blue, alpha)
        if self.playerlibObject.weapon is not None:
            self.playerlibObject.setWeaponColor(red, green, blue, alpha)

    def fade(self, alpha, timeLength, stepSize=None):
        """
        Fade a player to a given alpha over a certain time length. This creates
        a nice animation to altering the player's transparency rather than
        giving an explicit value in colour.

        @param int alpha The alpha to fade to
        @param float timeLength The amount of time the fade will take.
        @param int stepSize The amount to alter the fade by
        """
        self.cancelDelayed("fade")
        if stepSize is None:
            totalAlphaChange = self.attributes['minAlpha'] - alpha
            stepSize = totalAlphaChange / float(timeLength)
            stepSize = stepSize / 10.

        currentAlpha = self.attributes['minAlpha']
        currentAlpha -= stepSize
        r, g, b, a = self.playerlibObject.getColor()
        if abs(alpha - currentAlpha) < stepSize:
            currentAlpha = alpha
        self.playerlibObject.setColor(r, g, b, int(round(currentAlpha)))
        self.attributes['minAlpha'] = currentAlpha
        if currentAlpha != alpha:
            self.delayedName(0.1, "fade", self.fade, 
                            (alpha, timeLength, stepSize))

    def freeze(self, delay=None):
        """
        Freeze the player which prevents them from walking; but they can still
        shoot and look around.

        @param float delay Amount of seconds to freeze the player
        """
        self.playerlibObject.freeze = 1
        if delay is not None:
            self.delayed(delay, self.unFreeze)

    def unFreeze(self):
        """
        This command unfreeze a player so that they can continue moving around
        the map.
        """
        self.playerlibObject.freeze = 0

    def god(self, delay=None):
        """
        Turns a player into a god which prevents them from taking any damage.
        After a specific delay, it turns them back into a regular human.

        @param float delay Amount of seconds this mode lasts for
        """
        self.playerlibObject.godmode = 1
        if delay is not None:
            self.delayed(delay, self.unGod)

    def unGod(self):
        """
        Turns a god into a normal player which allows them to take damage again.
        """
        self.playerlibObject.godmode = 0

    def blind(self, delay, alpha=255, type = 2, red = 0, green = 0, blue = 0):
        """
        Apply on overlay to a person's screen and starts a loop which will
        continue update the blind throughout the delay time.

        @param float delay The amount of time that the person will be blinded
        @param int alpha The opacity of the overlay
        @param int type The type of the fade:
                          - 0 = No fade
                          - 1 = Fade Out
                          - 2 = fade in
        @param int red The red pigment of the overlay
        @param int green The green pigment of the overlay
        @param int blue The blue pigment of the overlay
        """
        self.cancelDelayed("blind")
        self.__updateBlind(time.time() + delay, alpha, type, red, green, blue)

    def __updateBlind(self, endTime, alpha, type = 2, red = 0, green = 0,
                                                                      blue = 0):
        """
        Since the usermessage fade works on FPS, we need to keep reapplying
        the fade so we can cancel it whenever we want.
        
        @internal
        @param float endTime The system's time since epoch that the fade ends
        @param int alpha The opacity of the blind
        @param int type The type of the blind
        @param int red The red pigment of the overlay
        @param int green The green pigment of the overlay
        @param int blue The blue pigment of the overlay
        """
        if time.time() < endTime:
            es.usermsg('create', 'fade', 'Fade')
            es.usermsg('write', 'short', 'fade', 5)     # Frames To fade
            es.usermsg('write', 'short', 'fade', 100)   # Frames to stay faded
            es.usermsg('write', 'short', 'fade', type)  # Type of fade
            es.usermsg('write', 'byte',  'fade', red)   # Red
            es.usermsg('write', 'byte',  'fade', green) # Green
            es.usermsg('write', 'byte',  'fade', blue)  # Blue
            es.usermsg('write', 'byte',  'fade', alpha) # Alpha
            es.usermsg('send', 'fade', self.userid)
            es.usermsg('delete', 'fade')
            self.delayedName(0.1, "blind", self.__updateBlind, (endTime, alpha,
                                                                type, red,
                                                                green, blue))

    def burn(self, delay=None):
        """
        Ignites a player and sets them on fire. This will create a slow decay
        effect, slow the player, apply an effect and play a burning noise for
        the player.

        @param float delay The amount of time the burn will last.
        """
        time = 9999 if delay is None else delay
        if time == 0:
            time = 9999
        if delay:
            es.fire(self.userid, "!self", "IgniteLifetime", time)
        else:
            es.fire(self.userid, "!self", "IgniteLifetime")

    def extinguish(self):
        """
        Removes the flame, decay and sound from the player; effectively
        extinguishing the player.
        """
        handle = es.getplayerhandle(self.userid)
        for entity in es.createentitylist("entityflame"):
            if es.getindexprop(entity, "CEntityFlame.m_hEntAttached") == handle:
                es.remove(entity)

    def unBurn(self):
        """
        Execute the same functionality of extinguish; the only reason I'm
        keeping this function here is for backwards compatibility. Since
        extinguish as a function name is more sensible, we advice using that.

        @depricated
        """
        self.extinguish()

    def changeGravity(self, amount):
        """
        Modifieds the player's current gravity value. This will increment the
        value by a given value rather than explicitly altering it to a new
        value.

        @param float amount Amount to increment the gravity by.
        """
        self.attributes['minGravity'] += amount
        self.__reapplyGravity()

    def setGravity(self, value):
        """
        Sets the player's current gravity value. This will change it to an
        explicit value rather than incrementing the current value.

        @param float value The new value for the player's gravity.
        """
        self.attributes['minGravity'] = value
        self.__reapplyGravity()

    def __reapplyGravity(self):
        """
        Reapplies the gravity of the value within the player's attributes.

        @internal
        """
        self.cancelDelayed("gravity")
        es.server.es_fire(self.userid, '!self addoutput "gravity %s" 0.1 1' %
                                                  self.attributes["minGravity"])
        self.delayedName(0.1, "gravity", self.__reapplyGravity)

    def speed(self, amount):
        """
        Applies a new value to the player's speed enabling us to alter how
        fast the player's move

        @param int amount The new value for the player's speed
        """
        if amount:
            self.attributes['maxSpeed'] = amount
            self.playerlibObject.speed = amount

    def speedAdd(self, amount):
        """
        Adds a value to their current speed and updates the player's attribute.
        This increments the player's current speed rather than explicitly
        assigning a new value.

        @param float amount The amount of speed to add to the player's speed
        """
        currentSpeed = self.attributes['maxSpeed']
        currentSpeed += amount
        self.attributes['maxSpeed'] = currentSpeed
        self.speed(currentSpeed)

    def heal(self, amount):
        """
        Heals a player by the given amount. This command always ensures that
        the player will never go over their maximum health.
        
        @param int amount Amount of health to heal the player.
        """
        health  = self.playerlibObject.health
        health += amount
        health = min(health, self.attributes['maxHealth'])
        self.playerlibObject.health = health

    def health(self, amount):
        """
        Changes the current and maximum health of the player, and updates the
        attributes accordingly.

        @param int amount The maximum health of a player
        """
        self.attributes['maxHealth'] = amount
        self.playerlibObject.health = amount

    def healthAdd(self, amount):
        """
        Changes the current and maximum health of the player, and updates the
        attributes accordingly. This increments the current health rather than
        explicitly assigning a new value.

        @param int amount The maximum health of a player
        """
        self.attributes['maxHealth'] += amount
        self.playerlibObject.health = self.attributes['maxHealth']

    def saveLife(self, amount):
        """
        This command will raise the player's health above their maximum health, 
        but won't reassign their maxHealth attribute. This is used to go over
        their maximum health for a very short while.

        @param int amount The amount of health to add to the player
        """
        self.playerlibObject.health += amount

    def armor(self, amount):
        """
        Assigns the armor of a player to an explicit value

        @game Counter-Strike Source
        @param int amount The new armor value of the player
        """
        self.attributes['maxArmor'] = amount
        self.playerlibObject.armor = amount

    def armorAdd(self, amount):
        """
        Increments the armor of a player by a given value.

        @game Counter-Strike Source
        @param int amount The amount of armor to add to the player
        """
        self.attributes['maxArmor'] += amount
        self.playerlibObject.armor = self.attributes['maxArmor']

    def clip(self, amount, slot):
        """
        Reassigns the clip value of a weapon, slot or weaponlib tag to a given
        amount. Explicitly assigns a new value.

        @param int amount The new clip value of the weapon.
        @param int|string slot A weapon slot, or tag for the weapon
        """
        handle  = es.getplayerhandle(self.userid)
        actualSlot = None
        weaponList = []
        if isinstance (slot, int):
            actualSlot = slot
            weaponList = weaponlib.getWeaponList("#all")
        elif isinstance(slot, basestr):
            if slot.isdigit():
                actualSlot = int(slot)
                weaponList = weaponlib.getWeaponList("#all")
            else:
                if not slot.startswith("#"):
                    slot = "#%s" % slot
                weaponList = weaponlib.getWeaponList(slot)

        for weapon in weaponList:
            for index in weapon.indexlist:
                if es.getindexprop(index,
                              "CBaseEntity.m_hOwnerEntity") == handle:
                    if actualSlot is not None and weapon.slot != actualSlot:
                        continue
                    prop = "CBaseCombatWeapon.LocalWeaponData.m_iClip1"
                    es.setindexprop(index, prop, amount)

    def clipAdd(self, amount, slot):
        """
        Adds to the clip value of a weapon, slot or weaponlib tag to a given
        amount. Increments the current value by a certain amount.

        @param int amount The amount of bullets to add in the clip.
        @param int|string slot A weapon slot, or tag for the weapon
        """
        handle  = es.getplayerhandle(self.userid)
        actualSlot = None
        weaponList = []
        if isinstance (slot, int):
            actualSlot = slot
            weaponList = weaponlib.getWeaponList("#all")
        elif isinstance(slot, basestr):
            if slot.isdigit():
                actualSlot = int(slot)
                weaponList = weaponlib.getWeaponList("#all")
            else:
                if not slot.startswith("#"):
                    slot = "#%s" % slot
                weaponList = weaponlib.getWeaponList(slot)
        for weapon in weaponList:
            for index in weapon.indexlist:
                if es.getindexprop(index,
                              "CBaseEntity.m_hOwnerEntity") == handle:
                    if actualSlot is not None and weapon.slot != actualSlot:
                        continue
                    prop = "CBaseCombatWeapon.LocalWeaponData.m_iClip1"
                    clipCount = es.getindexprop(index, prop)
                    clipCount += amount
                    es.setindexprop(index, prop, clipCount)

    def ammo(self, amount, slot):
        """
        Reassigns the ammo value of a weapon, slot or weaponlib tag to a given
        amount. Explicitly assigns a new value.

        @param int amount The new ammo value of the weapon.
        @param int|string slot A weapon slot, or tag for the weapon
        """
        handle  = es.getplayerhandle(self.userid)
        actualSlot = None
        weaponList = []
        if isinstance (slot, int):
            actualSlot = slot
            weaponList = weaponlib.getWeaponList("#all")
        elif isinstance(slot, basestr):
            if slot.isdigit():
                actualSlot = int(slot)
                weaponList = weaponlib.getWeaponList("#all")
            else:
                if not slot.startswith("#"):
                    slot = "#%s" % slot
                weaponList = weaponlib.getWeaponList(slot)
        for weapon in weaponList:
            for index in weapon.indexlist:
                if es.getindexprop(index,
                              "CBaseEntity.m_hOwnerEntity") == handle:
                    if actualSlot is not None and weapon.slot != actualSlot:
                        continue
                    es.setplayerprop(index, weapon.prop, amount)

    def ammoAdd(self, amount, slot):
        """
        Adds to the ammo value of a weapon, slot or weaponlib tag to a given
        amount. Increments the current value by a certain amount.

        @param int amount The amount of bullets to add in the ammo.
        @param int|string slot A weapon slot, or tag for the weapon
        """
        handle  = es.getplayerhandle(self.userid)
        actualSlot = None
        weaponList = []
        if isinstance (slot, int):
            actualSlot = slot
            weaponList = weaponlib.getWeaponList("#all")
        elif isinstance(slot, basestr):
            if slot.isdigit():
                actualSlot = int(slot)
                weaponList = weaponlib.getWeaponList("#all")
            else:
                if not slot.startswith("#"):
                    slot = "#%s" % slot
                weaponList = weaponlib.getWeaponList(slot)
        for weapon in weaponList:
            for index in weapon.indexlist:
                if es.getindexprop(index,
                              "CBaseEntity.m_hOwnerEntity") == handle:
                    if actualSlot is not None and weapon.slot != actualSlot:
                        continue
                    ammoCount = es.getplayerprop(index, weapon.prop)
                    ammoCount += amount
                    es.setplayerprop(index, weapon.prop, ammoCount)

    def drain(self, damage, delay, time, attacker=None):
        """
        Commence a drain which will damage the user a specific amount each
        iteration.

        @param int damage Amount of damage to deal each drain loop
        @param float delay Amount of time (in seconds) between each delay
        @param float time Amount of time (in seconds) that the drain will last
        @param int attacker The person who is credited for the kill
        """
        newDelay = time - delay
        if newDelay >= 0:
            self.damage(damage, 32, attacker)
            self.blind(.3, 50, red=255)
            self.delayedName(delay, "drain", self.drain, (damage, delay,
                                                          newDelay, attacker))

    def resetDrain(self):
        """
        Stops any current active drain from a player.
        """
        self.cancelDelayed("drain")

    def drop(self):
        """
        Force a player to drop their weapons
        """
        spe.dropWeapon(self.userid, spe.getActiveWeapon(self.userid))

    def drug(self, time=None):
        """
        Apply an effect to this paricular player to ensure that their vision is
        distorted.
        
        @param float time Amount of time the drug will be active
        """
        if DIRECTORY == "dod":
            """ DOD FOV isn't "impressive" so we'll use an overlay """
            es.cexec(self.userid,
                                "r_screenoverlay effects/tp_eyefx/tp_eyefx.vmt")
        else:
            es.setplayerprop(self.userid, 'CBasePlayer.m_iDefaultFOV', 155)
        if time is not None:
            self.delayed(time, self.UnDrug)

    def unDrug(self):
        """
        Remove any vision distortion used by the drug command
        """
        if DIRECTORY == "dod":
            es.cexec(self.userid, "r_screenoverlay 0")
        else:
            es.setplayerprop(self.userid, 'CBasePlayer.m_iDefaultFOV', 90)

    def drunk(self, delay=None):
        """
        Begin an effect which will continually affect and alter the FOV and
        create an animated eye distortion on the user.

        @param float delay The amount of time this effect will last
        """
        self.__drunkLoop(time.time() + delay)

    def __drunkLoop(self, endTime, boolDown=True):
        """
        This is the command which affects the player's FOV; essentially
        distorting their vision. This will be executed until either the delay
        is canceled or the ending time is reached. Essentially all this does is
        alter their FOV by 10 each iteration.

        @param float endTime The seconds since epoch that the effect will end
        @param bool boolDown Whether or not the current effect is deducting or
                             adding to the FOV.
        """
        if time.time() <= endTime:
            fov = es.getplayerprop(self.userid, 'CBasePlayer.m_iDefaultFOV')
            if 40 < fov < 90:
                if boolDown:
                    fov -= 10
                else:
                    fov += 10
            elif fov == 40:
                fov += 10
                boolDown = False
            elif fov == 90:
                boolDown = True
                fov -= 10
            es.setplayerprop(self.userid, 'CBasePlayer.m_iDefaultFOV', fov)
            self.delayedName(0.2, "drunk", self.drunkLoop, (endTime, boolDown), True)
        else:
            es.setplayerprop(self.userid, 'CBasePlayer.m_iDefaultFOV', 90)

    def sobre(self):
        """
        Remove any drunk effect from the user, essentially making them sobre
        again.
        """
        self.cancelDelayed("drunk")

    def getTeleSafe(self, x, y, z, callback=None, *args):
        """
        Returns if the vector designated by (x,y,z) is safe to teleport to.
        
        @depricated
        @broken
        @param float x The X coordinate of the vector
        @param float y The Y coordinate of the vector
        @param float z The Z coordinate of the vector
        @param function callback A function callback after we have tested
        @param tuple args Any additional arguments to pass into the callback
        @return bool Whether or not that position is safe to teleport to
        """
        raise NotImplementedError("The function getTeleSafe no longer exists")

    def getWallBetween(self, targetPlayer, callback=None, *args, **kw):
        """
        Returns if there is a wall between this player and the target player.

        @param integer targetPlayer The target player's ID
        @param function callback Whether or not a callback function will be
                                 called after the value has been found
        @param args Any additional unnamed arguments to pass to the callback
        @param kw Any additional named keywords to pass to the callback
        @return bool Whether or not there is a wall between players
        """
        value = self.playerlibObject.isObstructionBetween(targetPlayer)
        if callback is None:
            return value
        callback(self.userid, value, *args, **kw)

    def getViewAngles(self):
        """
        Retrieves the current pitch, yaw and roll values for a given player.

        @return tuple The three angles for the current player's view
        """
        return self.playerlibObject.getViewAngle()

    def getViewCoord(self, callback=None, *args, **kw):
        """
        Retrieves the coordinates at the position where the player is looking.
        
        @param function callback Whether or not a callback function will be
                                 called after the value has been found
        @param args Any additional unnamed arguments to pass to the callback
        @param kw Any additional named keywords to pass to the callback
        @return tuple A 3-itemed tuple containing the x,y,z of the view coords
        """
        values = self.playerlibObject.getViewCoord()
        if callback is None:
            return values
        callback(self.userid, values[0], values[1], values[2], *args, **kw)

    def getViewPlayer(self, callback=None, *args, **kw):
        """
        Returns the player that this user is looking at. If the player is not
        looking at any other character, then state that.

        @param function callback Whether or not a callback function will be
                                 called after the value has been found
        @param args Any additional unnamed arguments to pass to the callback
        @param kw Any additional named keywords to pass to the callback
        @return int|None The player (if any) that this user is looking at
        """
        index = self.getViewProp()
        if not index:
            if callback is None:
                return None
        foundPlayer = None
        for player in playerlib.getPlayerList("#all"):
            if player.index == index:
                foundPlayer = player.userid
                if callback is None:
                    return foundPlayer
                break
        if callback is None:
            return foundPlayer
        callback(self.userid, foundPlayer, *args, **kw)

    def getViewProp(self, callback=None, *args, **kw):
        """
        Returns the prop index the user is looking at. If the player is not
        currently looking at any prop, then return None.

        @param function callback Whether or not a callback function will be
                                 called after the value has been found
        @param args Any additional unnamed arguments to pass to the callback
        @param kw Any additional named keywords to pass to the callback
        @return int|None The index of the prop that this user is looking at
        """
        foundIndex = None
        es.entsetname(self.userid, "__viewed_prop")
        for index in es.createentitylist():
            if (es.entitygetvalue(index, "TargetName") != "__viewed_prop"):
                continue
            foundIndex = index
            es.entitysetvalue(index, "TargetName", "")
            break
        if callback is None:
            return foundIndex
        callback(self.userid, foundIndex, *args, **kw)
        
    def isStuck(self, callback, *args, **kw):
        """
        Checks if a player is currently stuck. This function will push a player
        by a miniscule amount and if their position does not differ from the
        original position, then they are stuck.

        @param function callback The function callback executed when we have a
                                 result
        @param tuple args Any additional arguments to pass into the callback
        @param dict kw Any additional keywords to pass into the callback
        """
        self.push(0, 0, 10)
        location = es.getplayerlocation(self.userid)
        self.delayed(0.1, self.__checkIsStuck, (location, callback, args, kw))

    def __checkIsStuck(self, location, callback, args, kw):
        """
        This is executed after the delay from the isStuck function. This checks
        if the locations now differ from the starting location; if not, then
        the player is stuck.

        @param tuple location (x,y,z) tuple of the original location
        @param function callback The function callback executed when we have a
                                 result
        @param tuple args Any additional arguments to pass into the callback
        @param dict kw Any additional keywords to pass into the callback
        """
        currentLocation = es.getplayerlocation(self.userid)
        callback(bool(location == currentLocation), self.userid, *args, **kw)

    def isDead(self):
        """
        Retrieve whether or not a player is dead
        
        @return bool Whether or not a player is dead
        """
        return bool(es.getplayerprop(self.userid,'CBasePlayer.pl.deadflag'))

    def viewCone(self, filter, coneAngle, distance, callback=None, *args, **kw):
        """
        Retreives a list of all the players within a specified view cone, and
        either returns them or executes a function for each player.

        @param str filter A filter for all the users to return inside the cone
        @param float coneAngle The angle of the cone (90 = player's actual view
                                                           cone)
        @param float distance The distance of the view cone
        @param function callback The function callback executed when we have a
                                 result
        @param tuple args Any additional arguments to pass into the callback
        @param dict kw Any additional keywords to pass into the callback
        @return tuple All the players inside the specified view cone
        """
        foundPlayers = []
        originalVector = vecmath.Vector(es.getplayerlocation(self.userid))
        viewVector = vecmath.Vector(self.playerlibObject.viewVector())
        for target in playerlib.getUseridList(filter):
            targetVector = vecmath.vector(es.getplayerlocation(target))
            vectorBetween = targetVector - originalVector
            
            try:
                angle = math.degrees(vecmath.angle(vectorBetween, viewVector))
            except ZeroDivisionError:
                continue

            if angle <= coneAngle * 0.5 and vectorBetween.length() < distance:
                foundPlayers.append(target)

        if callback is None:
            return tuple(foundPlayers)
        for player in foundPlayers:
            callback(player, self.userid, *args, **kw)

    def nearCoord(self, xBound, yBound, zBound, x, y, z, callback=None,
                                             ident="#all", *args, **kw):
        """
        This function retrieves all the players within an x-y-z boundary from
        the x-y-z origin. It will then either return the tuple, or execute a
        function passing userid and the 'victim' into the callback.

        @param float xBound The boundary for the x axis
        @param float yBound The boundary for the y axis
        @param float zBound The boundary for the z axis
        @param float x The x axis origin
        @param float y The y axis origin
        @param float z The z axis origin
        @param function callback The function callback executed when we have a
                                 result
        @paran str ident The identifier to test for qualification
        @param tuple args Any additional arguments to pass into the callback
        @param dict kw Any additional keywords to pass into the callback
        @return tuple Container for all users within the boundaries from origin
        """
        players = []
        for player in playerlib.getUseridList(ident):
            if player != self.userid:
                targetX, targetY, targetZ = es.getplayerlocation(player)
                x = abs(x - targetX)
                y = abs(y - targetY)
                z = abs(z - targetZ)
                if x <= xBound and y <= yBound and z <= zBound:
                    if callable(callback):
                        function(player, self.userid, *args, **kw)
                    players.append(player)
        return tuple(players)

    def getNearCoordList(self, xBound, yBound, zBound, x, y, z, ident="#all"):
        """
        Tests to see which players are within x,y,z boundaries of the x,y,z
        origin. This method is depricated as getNearCoord will now return a
        list if no callback is specified.
        
        @depricated
        @param float xBound The boundary for the x axis
        @param float yBound The boundary for the y axis
        @param float zBound The boundary for the z axis
        @param float x The x axis origin
        @param float y The y axis origin
        @param float z The z axis origin
        @paran str ident The identifier to test for qualification
        @return tuple Container for all users within the boundaries from origin
        """
        return self.nearCoord(xBound, yBound, zBound, x, y, z, ident)

    def near(self, distance, callback=None, ident='#all', *args, **kw):
        """
        Tests to see which players are within a certain distance of this palyer.
        We will ensure we have a list of all the players and if no callback, we
        shall return this list.

        @param float distance The amount of game units to test for qualification
        @param function callback The function callback executed when we have a
                                 result
        @paran str ident The identifier to test for qualification
        @param tuple args Any additional arguments to pass into the callback
        @param dict kw Any additional keywords to pass into the callback
        @return tuple Container for all users within the boundaries from origin
        """
        playerList = []
        x, y, z = es.getplayerlocation(self.userid)
        for player in playerlib.getUseridList(ident + ',#alive'):
            if player != self.userid:
                targetX, targetY, targetZ = es.getplayerlocation(player)
                playerDistance = ((x - targetX) ** 2 + (y - targetY) ** 2 +
                                                      (z - targetZ) ** 2) ** 0.5
                if playerDistance <= distance:
                    if callable(callback):
                        callback(player, self.userid, *args, **kw)
                    playerList.append(player)
        return playerList

    def shake(self, time, violence):
        """
        Shakes the players screen for a designated time limit.

        @param float time The amount of seconds the shake will last
        @param float violence How violent the shake will be
        """
        es.usermsg('create', 'shake', 'Shake')
        es.usermsg('write', 'byte',  'shake', 0)
        es.usermsg('write', 'float', 'shake', violence)
        es.usermsg('write', 'float', 'shake', 1.0)
        es.usermsg('write', 'float', 'shake', time)
        es.usermsg('send', 'shake', self.userid)
        es.usermsg('delete', 'shake')

    def model(self, path):
        """
        Assigns a new model / skin to the player. This makes the player look
        differently than the normal skins. This is not 100% safe and is liable
        to crashing. Custom models also need to be downloaded first via the
        es.stringtable function.

        @param str path The path from the ../models/ directory where the model
                        is stored on the server.
        """
        self.playerlibObject.model = path

    def spawn(self):
        """
        Brings this player back to life if they're dead.
        """
        if self.isDead():
            spe.respawn(self.userid)

    def push(self, x, y, z):
        """
        Push a player with an x, y and z force

        @param float x The force of the player's x axis
        @param float y The force on the player's y axis
        @param float y The force on the player's z axis
        """
        self.playerlibObject.push(x, y, z)

    def pushTo(self, x, y, z, force):
        """
        
         a player to a certain coordinate on the map. They will be pushed at
        a certain force, but most likely will not meet their destination due to
        objects blocking their way reducing their velocity.
        
        @param float x The x coordinate on the map.
        @param float y The y coordinate on the map.
        @param float z The z coordinate on the map.
        @param float force The force of the push; 1 = normal
        """
        startingVector = vecmath.Vector(es.getplayerlocation(self.userid))
        endingVector = vecmath.Vector((x, y, z))
        vectorBetween = endingVector - startingVector
        vectorBetween *= force
        es.setplayerprop(self.userid, "CBasePlayer.localdata.m_vecBaseVelocity",
                                      str(vectorBetween))

    def areaRegen(self, teamFilter, distance, amount, delay):
        """
        Start a regeneration which has an aura effect to heal everybody within
        a certain distance around this player.

        @param teamFilter Designates which team this regen will apply to
        @param float distance The distance (in units) that the aura will apply
        @param int amount The amount of health to heal
        """
        teamFilter = self.getPlayerlibFilters(teamFilter)
        x, y, z  = es.getplayerlocation(self.userid)
        deadProp = 'CBasePlayer.pl.deadflag'
        players = playerlib.getUseridList(teamFilter)
        players = filter(lambda x: not es.getplayerprop(x, deadProp, players))
        for player in players:
            if player == self.userid:
                continue
            targetX, targetY, targetZ = es.getplayerlocation(player)
            if ((targetX - x) ** 2 + (targetY - y) ** 2 +
                                        (targetZ - z) ** 2) ** 0.5 <= distance:
                playerlib.getPlayer(player).health += amount
        self.delayed(delay, self.areaRegen, (team, distance, amount, delay))

    def areaDamage(self, teamFilter, distance, amount):
        """
        Damage everyone in a specific distance around the player.

        @param teamFilter Designates which team this AOE damage will apply to
        @param float distance The distance (in units) that the aura will apply
        @param int amount The amount of damage to give
        """
        teamFilter = self.getPlayerlibFilters(teamFilter)
        x, y, z  = es.getplayerlocation(self.userid)
        deadProp = 'CBasePlayer.pl.deadflag'
        players = playerlib.getUseridList(teamFilter)
        players = filter(lambda x: not es.getplayerprop(x, deadProp, players))
        for player in players:
            if player == self.userid:
                continue
            targetX, targetY, targetZ = es.getplayerlocation(player)
            if ((targetX - x) ** 2 + (targetY - y) ** 2 +
                                        (targetZ - z) ** 2) ** 0.5 <= distance:
                attacker = self.userid
                if playerlib.getPlayer(player).health > damage:
                    attacker = player
                
                weapon = weaponlib.getWeapon(weapon)
                playerlibObject = playerlib.getPlayer(player)
                index = playerlibObject.index
                targetName = es.entitygetvalue(index, "targetname")
                es.setentityname(index, "wcs_damage_player")
                es.server.es_fire(attacker, "point_hurt", "kill")
                index = es.createentity("point_hurt")
                es.entitysetvalue(index, "Damage", amount)
                es.entitysetvalue(index, "DamageType", 32)
                es.entitysetvalue(index, "DamageTarget", "wcs_damage_player")
                if not weapon and attacker != player:
                    attackerlibObject = playerlib.getPlayer(attacker)
                    weapon = weaponlib.getWeapon(attackerlibObject.weapon)
                if weapon:
                    es.entitysetvalue(index, "classname", weapon.name)
                es.spawnentity(index)
                es.server.es_fire(atacker, "point_hurt", "Hurt")
                es.setentityname(index, targetName)

    def delayed(self, duration, callback, parameters=(), 
                            removeOnRoundEnd=True, name=None):
        """
        Creates a delay to execute a callback passing any parameters to the
        callback. The advantage of this is the fact each delay is unique to
        the user so no name collisions, and these delays can be cancelled
        automatically when we reset the attributes.

        @param float duration The duration of the delay
        @param function callback The callback function to execute
        @param list parameters Container for the arguments passed to callback
        @param bool removeOnRoundEnd Whether or not the delay is removed at
                                     player death / round end
        """
        if name is not None:
            self.delayedName(duration, name, callback, parameters, 
                             removeOnRoundEnd)
        else:
            if removeOnRoundEnd is True:
                name = str(len(self.attributes['delayList']) + 1)
                name += str(self.userid)
                gamethread.delayedname(duration, name, callback, parameters)
                self.attributes['delayList'].append(name)
            else:
                gamethread.delayed(duration, callback, parameters)

    def delayedName(self, duration, name, callback, parameters=(), 
                    removeOnRoundEnd=True):
        """
        Creates a delay to execute a callback passing any parameters to the
        callback. The advantage of this is the fact each delay is unique to
        the user so no name collisions. Uses a custom name to allow for explicit
        cancelling through cancelDelayed function.

        @param float duration The duration of the delay
        @param str name The name of the delay
        @param function callback The callback function to execute
        @param list parameters Container for the arguments passed to callback
        """
        name += str(self.userid)
        if removeOnRoundEnd is True:
            gamethread.delayedname(duration, name, callback, parameters)
            self.attributes['delayList'].append(name)
        else:
            gamethread.delayedname(duration, name, callback, parameters)

    def cancelDelayed(self, name):
        """
        Cancels any current delays by the given name and removes them from the
        delay list.

        @param str name The name of the delay to cancel
        """
        name += str(self.userid)
        gamethread.cancelDelayed(name)
        if name in self.attributes['delayList']:
            self.attributes['delayList'].remove(name)

    def addItem(self, itemName, count=1):
        """
        Adds an item into the player's current item stash. This allows us to
        have a single object manage the item count for a player's item.
        
        @param str itemName The name of the item to add to the player's stash
        @param int count The amount of these items to add to the stash
        """
        if itemName in self["items"]:
            self["items"][itemName].count += count
        else:
            itemObject = PlayerItem(itemName, count)
            self["items"][itemName] = itemObject
            
    def removeItem(self, itemName, count=-1):
        """
        Removes an item from the player's count. This allows us to either
        decrease the value count of the item, or remove it completely.
        
        @param str itemName The name of the item to decrement / remove
        @param int count The amount of items to remove, -1 = remove all items
        """
        if itemName in self["items"]:
            if count == -1:
                del self["items"][itemName]
            else:
                self["items"][itemName].count -= count
                if self["items"][itemName].count <= 0:
                    del self["items"][itemName]
        
    def getItem(self, itemName):
        """
        Gets the item object of a particular item.
        
        @param str itemName The name of the item to retrieve
        @return PlayerItem The relevant player's item retrieved by the name
        """
        if itemName in self["items"]:
            return self["items"][itemName]
        return PlayerItem(itemName, 0)
    
    def getCash(self):
        """
        Returns the amount of cash a player current has.
        
        @return int The amount of cash the player has
        """
        return int(self.playerlibObject.cash)
    
    def setCash(self, amount):
        """
        Reassigns the cash to a new value.
        
        @param int amount The amount of cash to add to the player's cash
        """
        self.playerlibObject.cash = amount

    def removeWeapon(self, weaponType, weaponCount = None):
        """ Return the true name of the weapon, then iterate throug an entity list, testing
            if the classname is equa too the weapon or the player owns the weapon; if so, increment
            a counting value, if the counting value is only 1, strip player so they can't see their
            weapon, else, just remove the weapon index. """
        if not es.exists('userid', self.userid):
            return
        weapon = returnWeaponNameFromEstSyntax(weaponType, self.userid)
        if weapon is None:
            return
        if not weapon.startswith('weapon_'):
            weapon = 'weapon_' + weapon
        if weapon != 'weapon_' and weapon != 'weapon_0':
            handle      = es.getplayerhandle(self.userid)
            plus = False
            if weaponCount is None:
                plus = True
                weaponCount = 0
            entityList  = es.createentitylist()
            gotWeapon   = False
            for weaponEntity in entityList:
                if not entityList[weaponEntity]['classname'].startswith('weapon_'):
                    continue
                if es.getindexprop(weaponEntity, 'CBaseEntity.m_hOwnerEntity') == handle:
                    if plus:
                        weaponCount += 1
                    if entityList[weaponEntity]['classname'] == weapon:
                        gotWeapon = True
            if gotWeapon:
                if weaponCount > 1:
                    for entity in es.createentitylist(weapon):
                        if es.getindexprop(entity, 'CBaseEntity.m_hOwnerEntity') == handle:
                            if isOb:
                                if not self.__getitem__("_removedThisTick"):
                                    self.__setitem__("_removedThisTick", 1)
                                    self._safeRemove(entity)
                                    gamethread.delayed(0, self.__setitem__, ("_removedThisTick", 0))
                                else:
                                    gamethread.delayed(0, self.RemoveWeapon, (weaponType, weaponCount - 1))
                            else:
                                es.server.cmd('es_xremove %s' % entity)
                            gamethread.delayed(0, gamethread.delayed, (0, es.cexec, (self.userid, 'lastinv' )))
                            return
                else:
                    if isOb:
                        es.fire(self.userid, 'player_weaponstrip', 'kill')
                        es.give(self.userid, 'player_weaponstrip')
                        es.fire(self.userid, 'player_weaponstrip', 'strip')
                    else:
                        es.server.queuecmd('es_xfire %s player_weaponstrip kill' % self.userid)
                        es.server.queuecmd('es_xgive %s player_weaponstrip' % self.userid)
                        es.server.queuecmd('es_xfire %s player_weaponstrip strip' % self.userid)

    def _safeRemove(self, entity):
        """ This gives us the opportunity to ensure that the weapon is still here when we attempt to remove it """
        entityList = es.createentitylist()
        if entity in entityList and entityList[entity]['classname'] != "worldspawn":
            if isOb:
                es.remove(entity)
            else:
                es.server.queuecmd('es_xremove %s'%entity)

    def restrict(self, weaponType):
        """ Appends a weapon to the players 'restricted liist' so we can test if the player has a restricted weapon on clientCommandFilter
            or event item_pickup """
        if not es.exists('userid', self.userid):
            return
        if not weaponType.startswith('#'):
            weaponType = returnWeaponNameFromEstSyntax(weaponType, self.userid)
            if weaponType is None:
                return
        else:
            weaponType = weaponType.split(',')
            weaponlist = []
            for weaponTag in weaponType:
                weaponlist.extend(weaponlib.getWeaponNameList(weaponTag))
            for weapon in weaponlist:
                self.RemoveWeapon(weapon)
                self.attributes['Restricted'].append(weapon)

    def unRestrict(self, weaponType):
        """ Removes a weapon to the players 'restricted liist' so we can test if the player has a restricted weapon on clientCommandFilter
            or event item_pickup """
        if not es.exists('userid', self.userid):
            return
        weaponType = returnWeaponNameFromEstSyntax(weaponType, self.userid)
        if weaponType is None:
            return
        if not weaponType.startswith('#'):
            weaponType = weaponType.replace('weapon_', '').lower()
            if weaponType in self.attributes['Restricted']:
                self.attributes['Restricted'].remove(weaponType)
        else:
            weaponType = weaponType.split(',')
            weaponlist = []
            for weaponTag in weaponType:
                weaponlist.extend(weaponlib.getWeaponNameList(weaponTag))
            for weapon in weaponlist:
                if weapon in self.attributes['Restricted']:
                    self.attributes['Restricted'].remove(weapon)
    
    class Attributes(dict):
        """
        A dictionary like object which will store any custom attributes. Default
        the dictionary items to what we want to store.
        """
        
        """ Assign the static default values """
        defaults = {}
        defaults['blockUltimate']  = False
        defaults['blockAbility']   = False
        defaults['jumpMultiplier'] = 1.0
        defaults['delayList']      = list()
        defaults['maxHealth']      = 100
        defaults['maxArmor']       = 0
        defaults['maxSpeed']       = 1.0
        defaults['minAlpha']       = 255.0
        defaults['minGravity']     = 1.0
        defaults['coolDownTimer']  = 0.0
        defaults['pendingRace']    = None
        defaults['toggleUltimate'] = False
        
        def __init__(self, *args):
            """
            Default constructor. Ensure that we initialize the dictionary
            constructor but also refresh the values so we start with default
            values.
            """
            dict.__init__(self, *args)
            self.refresh()
            self.__setitem__("items", PlayerItemStorage())
            
        def __getattr__(self, key):
            """
            A way to simulate having attribute access for a dictionary. Normally
            I wouldn't aprove of this, but since we are simulating an attribute
            class system, this is acceptable and preffered since x.maxHealth is
            more advisable than x['maxHealth'] when considering attributes.
            
            @param str key The attribute of which to retrieve
            @return mixed The values which is retrieved
            """
            if hasattr(dict, key):
                return getattr(dict, key)
            if not self.__contains__(key):
                raise AttributeError("'Attribute' object has no attribute '" +
                                      key + "'")
            return self.__getitem__(key)
            
        def __setattr__(self, key, value):
            """
            A way to simulate having attribute access for a dictionary. Normally
            I wouldn't approve of this, but since we are simulate an attribute
            class system, this is acceptable and preffered since x.maxHealth=100
            is more advisable than x['maxHealth'] = 100 when considering
            attributes.
            
            @param str key The name of the attribute
            @param mixed value The value of the attribute 
            """
            self.__setitem__(key, value)
                
        def __repr__(self):
            """
            How this class is represented in python. Return a string which
            simulates this object.
            """
            return "Attributes(%s)" % dict.__repr__(self)
        
        def refresh(self):
            """
            The only custom function for this object. Loop through the static
            variable defaults and ensure that all the values are assigned back
            to their default values. This will create the values if they don't
            yet exists.
            """
            for defaultKey, defaultValue in self.__class__.defaults.iteritems():
                self.__setitem__(defaultKey, defaultValue)
                
class PlayerItemStorage(dict):
    """
    This object is here to contian user items for a particular player. The
    reason why we subclass it from the dict object is to ensure that all values
    are PlayerItem objects and thus enforces consistency.
    """
    def __setitem__(self, key, value):
        """
        Executed when the attribute assignment is performed, we need to hook the
        dictionaries native ability and ensure the value being assigned is
        indeed of type PlayerItem. If not, then create a default PlayerItem
        object and call the dict __setitem__ function.
        
        @param str key The name of the item being assigned to the player
        @param int|PlayerItem The item count of the item
        """
        if not isinstance(value, PlayerItem):
            if not isinstance(value, int):
                raise ValueError("PlayerItemStorage expects type 'int' or " +
               "type 'PlayerItem' to be of value, instead received '%s'" %
               type(value).__name__)
            value = PlayerItem(key, value)   
        dict.__setitem__(self, key, value)
        
class PlayerItem(object):
    """
    This object will act as a structure for a custom object, allowing us to
    store multiple values within one single object. Since Python doesn't have
    structs we shall have to leave this as a custom class object.
    """
    def __init__(self, name, count):
        """
        Default constructor, ensure that the values are assigned to the object.
        
        @param str name The name of the item
        @param int count The amount of this item a particular user has
        """
        self.name = name
        self.count = count